﻿Public Class PickBox

    Private Const BOX_SIZE As Integer = 8
    Private BOX_COLOR As Color = Color.White
    ' Private m_container As ContainerControl
    Private m_control As Control = Nothing
    Private lbl As Label() = New Label(7) {}
    Private startl As Integer
    Private startt As Integer
    Private startw As Integer
    Private starth As Integer
    Private startx As Integer
    Private starty As Integer
    Private dragging As Boolean
    Private arrArrow As Cursor() = New Cursor() {Cursors.SizeNWSE, Cursors.SizeNS, Cursors.SizeNESW, Cursors.SizeWE, Cursors.SizeNWSE, Cursors.SizeNS, _
    Cursors.SizeNESW, Cursors.SizeWE}
    Private oldCursor As Cursor

    Private Const MIN_SIZE As Integer = 5

    ' 
    ' Constructor creates 8 sizing handles & wires mouse events 
    ' to each that implement sizing functions 
    ' 
    Public Sub New()
        For i As Integer = 0 To 7
            lbl(i) = New Label()
            lbl(i).TabIndex = i
            lbl(i).FlatStyle = 0
            lbl(i).BorderStyle = BorderStyle.FixedSingle
            lbl(i).BackColor = BOX_COLOR
            lbl(i).Cursor = arrArrow(i)
            lbl(i).Text = ""
            lbl(i).BringToFront()
            AddHandler lbl(i).MouseDown, AddressOf lbl_MouseDown
            AddHandler lbl(i).MouseMove, AddressOf lbl_MouseMove
            AddHandler lbl(i).MouseUp, AddressOf lbl_MouseUp
        Next
    End Sub


    ' 
    ' Wires a Click event handler to the passed Control 
    ' that attaches a pick box to the control when it is clicked 
    ' 
    Public Sub WireControl(ByVal ctl As Control)
        'AddHandler ctl.MouseDown, AddressOf SelectControl
        SetHandler(ctl)
    End Sub

    ''' <summary>
    ''' 子控件的Click事件处理方法
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks>
    ''' addded by hudan at 2008-9-19
    ''' </remarks>
    Private Sub SelectChildControl(ByVal sender As Object, ByVal e As MouseEventArgs)
        SelectControl(CType(sender, Control).Parent, e)
    End Sub

    Private Sub childctl_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        ctl_MouseDown(CType(sender, Control).Parent, e)
    End Sub

    Private Sub childctl_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
        ctl_MouseMove(CType(sender, Control).Parent, e)
    End Sub

    Private Sub childctl_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
        ctl_MouseUp(CType(sender, Control).Parent, e)
    End Sub

    Private Sub SetHandler(ByVal ctl As Control)
        AddHandler ctl.MouseDown, AddressOf ctl_MouseDown
        AddHandler ctl.MouseMove, AddressOf ctl_MouseMove
        AddHandler ctl.MouseUp, AddressOf ctl_MouseUp

        For Each c1 As Control In ctl.Controls
            AddHandler c1.MouseDown, AddressOf childctl_MouseDown
            AddHandler c1.MouseMove, AddressOf childctl_MouseMove
            AddHandler c1.MouseUp, AddressOf childctl_MouseUp
        Next
    End Sub
    ' 
    ' Attaches a pick box to the sender Control 
    '
    ' Private Sub SelectControl(ByVal sender As Object, ByVal e As EventArgs)
    '
    Private Sub SelectControl(ByVal sender As Object, ByVal e As MouseEventArgs)

        If m_control Is sender Then
            Exit Sub
        End If

        'If TypeOf m_control Is Control Then
        If m_control IsNot Nothing Then
            m_control.Cursor = oldCursor
            RemoveHandler m_control.MouseDown, AddressOf ctl_MouseDown
            RemoveHandler m_control.MouseMove, AddressOf ctl_MouseMove
            RemoveHandler m_control.MouseUp, AddressOf ctl_MouseUp

            '=======================================================
            'added by hudan
            For Each c1 As Control In m_control.Controls
                RemoveHandler c1.MouseDown, AddressOf childctl_MouseDown
                RemoveHandler c1.MouseMove, AddressOf childctl_MouseMove
                RemoveHandler c1.MouseUp, AddressOf childctl_MouseUp
            Next
            '=======================================================

            'Remove event any pre-existing event handlers appended by this class 

            m_control = Nothing
        End If

        m_control = DirectCast(sender, Control)
        AddHandler m_control.MouseDown, AddressOf ctl_MouseDown
        AddHandler m_control.MouseMove, AddressOf ctl_MouseMove
        AddHandler m_control.MouseUp, AddressOf ctl_MouseUp

        '=======================================================
        'added by hudan
        For Each c1 As Control In m_control.Controls
            AddHandler c1.MouseDown, AddressOf childctl_MouseDown
            AddHandler c1.MouseMove, AddressOf childctl_MouseMove
            AddHandler c1.MouseUp, AddressOf childctl_MouseUp
        Next
        '=======================================================

        If Not m_control.Parent.Controls.Contains(lbl(0)) Then
            For i As Integer = 0 To 7
                'Add event handlers for moving the selected control around 

                'Add sizing handles to Control's container (Form or PictureBox) 
                m_control.Parent.Controls.Add(lbl(i))
                lbl(i).BringToFront()
            Next
        End If


        'Position sizing handles around Control 
        MoveHandles()

        'Display sizing handles 
        ShowHandles()

        oldCursor = m_control.Cursor
        m_control.Cursor = Cursors.SizeAll

    End Sub

    'Public Sub Remove()
    '    HideHandles()
    '    m_control.Cursor = oldCursor
    'End Sub

    Private Sub ShowHandles()
        If m_control IsNot Nothing Then
            For i As Integer = 0 To 7
                lbl(i).Visible = True
            Next
        End If
    End Sub

    Public Sub HideHandles()
        For i As Integer = 0 To 7
            lbl(i).Visible = False
        Next
    End Sub

    Private Sub MoveHandles()
        Dim sX As Integer = m_control.Left - BOX_SIZE
        Dim sY As Integer = m_control.Top - BOX_SIZE
        Dim sW As Integer = m_control.Width + BOX_SIZE
        Dim sH As Integer = m_control.Height + BOX_SIZE
        Dim hB As Integer = BOX_SIZE / 2
        Dim arrPosX As Integer() = New Integer() {sX + hB, sX + sW / 2, sX + sW - hB, sX + sW - hB, sX + sW - hB, sX + sW / 2, _
        sX + hB, sX + hB}
        Dim arrPosY As Integer() = New Integer() {sY + hB, sY + hB, sY + hB, sY + sH / 2, sY + sH - hB, sY + sH - hB, _
        sY + sH - hB, sY + sH / 2}
        For i As Integer = 0 To 7
            lbl(i).SetBounds(arrPosX(i), arrPosY(i), BOX_SIZE, BOX_SIZE)
        Next
    End Sub

    Private Sub Movehandles(ByVal pt As Point)
        Dim sX As Integer = m_control.Left - BOX_SIZE
        Dim sY As Integer = m_control.Top - BOX_SIZE
        Dim sW As Integer = pt.X - m_control.Left + BOX_SIZE
        Dim sH As Integer = pt.Y - m_control.Top + BOX_SIZE
        Dim hB As Integer = BOX_SIZE / 2
        Dim arrPosX As Integer() = New Integer() {sX + hB, sX + sW / 2, sX + sW - hB, sX + sW - hB, sX + sW - hB, sX + sW / 2, _
        sX + hB, sX + hB}
        Dim arrPosY As Integer() = New Integer() {sY + hB, sY + hB, sY + hB, sY + sH / 2, sY + sH - hB, sY + sH - hB, _
        sY + sH - hB, sY + sH / 2}
        For i As Integer = 0 To 7
            lbl(i).SetBounds(arrPosX(i), arrPosY(i), BOX_SIZE, BOX_SIZE)
        Next
    End Sub

    ' Store control position and size when mouse button pushed over 
    ' any sizing handle 
    ' 
    Private Sub lbl_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        dragging = True
        startl = m_control.Left
        startt = m_control.Top
        startw = m_control.Width
        starth = m_control.Height

        Me.MoveHandles()
        HideHandles()
    End Sub

    ' 
    ' Size the picked control in accordance with sizing handle being dragged 
    ' 0 1 2 
    ' 7 3 
    ' 6 5 4 
    ' 
    Private Sub lbl_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
        Dim l As Integer = m_control.Left
        Dim w As Integer = m_control.Width
        Dim t As Integer = m_control.Top
        Dim h As Integer = m_control.Height
        If dragging Then
            Select Case DirectCast(sender, Label).TabIndex
                Case 0
                    ' Dragging top-left sizing box 
                    l = IIf(startl + e.X < startl + startw - MIN_SIZE, startl + e.X, startl + startw - MIN_SIZE)
                    t = IIf(startt + e.Y < startt + starth - MIN_SIZE, startt + e.Y, startt + starth - MIN_SIZE)
                    w = startl + startw - m_control.Left
                    h = startt + starth - m_control.Top
                    Exit Select
                Case 1
                    ' Dragging top-center sizing box 
                    t = IIf(startt + e.Y < startt + starth - MIN_SIZE, startt + e.Y, startt + starth - MIN_SIZE)
                    h = startt + starth - m_control.Top
                    Exit Select
                Case 2
                    ' Dragging top-right sizing box 
                    w = IIf(startw + e.X > MIN_SIZE, startw + e.X, MIN_SIZE)
                    t = IIf(startt + e.Y < startt + starth - MIN_SIZE, startt + e.Y, startt + starth - MIN_SIZE)
                    h = startt + starth - m_control.Top
                    Exit Select
                Case 3
                    ' Dragging right-middle sizing box 
                    w = IIf(startw + e.X > MIN_SIZE, startw + e.X, MIN_SIZE)
                    Exit Select
                Case 4
                    ' Dragging right-bottom sizing box 
                    w = IIf(startw + e.X > MIN_SIZE, startw + e.X, MIN_SIZE)
                    h = IIf(starth + e.Y > MIN_SIZE, starth + e.Y, MIN_SIZE)
                    Exit Select
                Case 5
                    ' Dragging center-bottom sizing box 
                    h = IIf(starth + e.Y > MIN_SIZE, starth + e.Y, MIN_SIZE)
                    Exit Select
                Case 6
                    ' Dragging left-bottom sizing box 
                    l = IIf(startl + e.X < startl + startw - MIN_SIZE, startl + e.X, startl + startw - MIN_SIZE)
                    w = startl + startw - m_control.Left
                    h = IIf(starth + e.Y > MIN_SIZE, starth + e.Y, MIN_SIZE)
                    Exit Select
                Case 7
                    ' Dragging left-middle sizing box 
                    l = IIf(startl + e.X < startl + startw - MIN_SIZE, startl + e.X, startl + startw - MIN_SIZE)
                    w = startl + startw - m_control.Left
                    Exit Select
            End Select
            l = IIf((l < 0), 0, l)
            t = IIf((t < 0), 0, t)
            m_control.SetBounds(l, t, w, h)
            'Me.MoveHandles()
            'Me.ShowHandles()
        End If
    End Sub

    ' 
    ' Display sizing handles around picked control once sizing has completed 
    ' 
    Private Sub lbl_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
        dragging = False
        MoveHandles()
        ShowHandles()
    End Sub


    ' 
    ' Get mouse pointer starting position on mouse down and hide sizing handles 
    ' 
    Private Sub ctl_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        m_control = sender

        If Not m_control.Parent.Controls.Contains(lbl(0)) Then
            For i As Integer = 0 To 7
                'Add event handlers for moving the selected control around 

                'Add sizing handles to Control's container (Form or PictureBox) 
                m_control.Parent.Controls.Add(lbl(i))
                lbl(i).BringToFront()
            Next
        End If


        'Position sizing handles around Control 
        MoveHandles()

        'Display sizing handles 
        ShowHandles()

        oldCursor = m_control.Cursor
        m_control.Cursor = Cursors.SizeAll


        dragging = True
        startx = e.X
        starty = e.Y
        HideHandles()
    End Sub

 

    ' 
    ' Reposition the dragged control 
    ' 
    Private Sub ctl_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
        If dragging Then
            Dim l As Integer = m_control.Left + e.X - startx
            Dim t As Integer = m_control.Top + e.Y - starty
            Dim w As Integer = m_control.Width
            Dim h As Integer = m_control.Height
            l = IIf((l < 0), 0, (IIf((l + w > m_control.Parent.ClientRectangle.Width), m_control.Parent.ClientRectangle.Width - w, l)))
            t = IIf((t < 0), 0, (IIf((t + h > m_control.Parent.ClientRectangle.Height), m_control.Parent.ClientRectangle.Height - h, t)))
            m_control.Left = l
            m_control.Top = t

        Else
            If e.Button = MouseButtons.Left Then
                startx = e.X
                starty = e.Y

                Me.MoveHandles()
                Me.ShowHandles()
            End If
        End If
    End Sub

    ' 
    ' Display sizing handles around picked control once dragging has completed 
    ' 
    Private Sub ctl_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
        dragging = False
        MoveHandles()
        ShowHandles()
    End Sub

    '当前选中控件
    Public ReadOnly Property CurrentSelectedControl() As Control
        Get
            Return m_control
        End Get
    End Property

End Class

